home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / clients / xcalc / math.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-12  |  20.9 KB  |  974 lines

  1. /* $XConsortium: math.c,v 1.17 91/07/25 17:51:34 rws Exp $
  2.  *
  3.  *  math.c  -  mathematics functions for a hand calculator under X
  4.  *
  5.  *  Author:    John H. Bradley, University of Pennsylvania
  6.  *                (bradley@cis.upenn.edu)
  7.  *                     March, 1987
  8.  *
  9.  *  RPN mode added and port to X11 by Mark Rosenstein, MIT Project Athena
  10.  *
  11.  *  Modified to be a client of the Xt toolkit and the Athena widget set by
  12.  *  Donna Converse, MIT X Consortium.  This is all that remains of the
  13.  *  original calculator, and it still needs to be rewritten.  The HP
  14.  *  functionality should be separated from the TI functionality.
  15.  *  Beware the HP functions: there are still errors here.
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <X11/Xos.h>
  20. #include <math.h>
  21. #include <signal.h>
  22. #if !defined(IEEE) && defined(SVR4)
  23. #include <siginfo.h>
  24. #endif
  25. #include <setjmp.h>
  26. #include "xcalc.h"
  27. #include <errno.h>
  28.  
  29. #ifdef _CRAY        /* kludge around Cray STDC compiler */
  30. double (*log_p)() = log;
  31. #define log ((*log_p))
  32. double (*exp_p)() = exp;
  33. #define exp ((*exp_p))
  34. double (*sqrt_p)() = sqrt;
  35. #define sqrt ((*sqrt_p))
  36. double (*log10_p)() = log10;
  37. #define log10 ((*log10_p))
  38. double (*atan2_p)() = atan2;
  39. #define atan2 ((*atan2_p))
  40. double (*asin_p)() = asin;
  41. #define asin ((*asin_p))
  42. double (*acos_p)() = acos;
  43. #define acos ((*acos_p))
  44. double (*atan_p)() = atan;
  45. #define atan ((*atan_p))
  46. double (*sin_p)() = sin;
  47. #define sin ((*sin_p))
  48. double (*cos_p)() = cos;
  49. #define cos ((*cos_p))
  50. double (*tan_p)() = tan;
  51. #define tan ((*tan_p))
  52. double (*pow_p)() = pow;
  53. #define pow ((*pow_p))
  54. #endif /* _CRAY */
  55.  
  56. #ifndef PI        /* sometimes defined in math.h */
  57. #define PI          3.14159265358979
  58. #endif
  59. #define E           2.71828182845904
  60. #define MAXDISP     11
  61. #define DEG 0        /* DRG mode.  used for trig calculations */
  62. #define RAD 1
  63. #define GRAD 2
  64. #define min(a,b) ((a) < (b) ? (a) : (b))
  65. #define max(a,b) ((a) > (b) ? (a) : (b))
  66. #define True    1
  67. #define False   0
  68.  
  69. #ifndef MSDOS
  70. extern int    errno;
  71. #endif
  72.  
  73. extern int    rpn;
  74. extern char     dispstr[];
  75. extern void draw();
  76. extern void ringbell();
  77. extern void setflag();
  78. extern void Quit();
  79.  
  80. #ifndef IEEE
  81.     jmp_buf env;
  82. #endif
  83.  
  84.  
  85. /* This section is all of the state machine that implements the calculator
  86.  * functions.  Much of it is shared between the infix and rpn modes.
  87.  */
  88.  
  89. int     flagINV, flagPAREN, flagM, drgmode;    /* display flags */
  90.  
  91. static double drg2rad=PI/180.0;  /* Conversion factors for trig funcs */
  92. static double rad2drg=180.0/PI;
  93. static int entered=1;  /* true if display contains a valid number.
  94.                           if==2, then use 'dnum', rather than the string
  95.                           stored in the display.  (for accuracy) 
  96.                           if==3, then error occurred, only CLR & AC work */
  97. /* entered seems to be overloaded - dmc */
  98. static int lift_enabled = 0;    /* for rpn mode only */
  99.  
  100. static int CLR    =0;  /* CLR clears display.  if 1, clears acc, also */
  101. static int OFF    =0;  /* once clears mem, twice quits */
  102. static int Dpoint=0;  /* to prevent using decimal pt twice in a # */
  103. static int clrdisp=1;  /* if true clears display before entering # */
  104. static int accset =0;
  105. static int lastop =kCLR;
  106. static int memop  =kCLR;
  107. static int exponent=0;
  108. static double acc =0.0;
  109. static double dnum=0.0;
  110. #define XCALC_MEMORY 10
  111. static double mem[XCALC_MEMORY] = { 0.0 };
  112.  
  113. /*
  114.  * The following is to deal with the unfortunate assumption that if errno
  115.  * is non-zero then an error has occurred.  On some systems (e.g. Ultrix), 
  116.  * sscanf will call lower level routines that will set errno.
  117.  */
  118.  
  119. void parse_double (src, fmt, dp)
  120.     char *src;
  121.     char *fmt;
  122.     double *dp;
  123. {
  124.     int olderrno = errno;
  125.  
  126.     (void) sscanf (src, fmt, dp);
  127.     errno = olderrno;
  128.     return;
  129. }
  130.  
  131.  
  132. /*********************************/
  133. int pre_op(keynum)
  134.      int keynum;
  135. {
  136.     if (keynum==-1) return(0);
  137.  
  138.     errno = 0;            /* for non-IEEE machines */
  139.  
  140.     if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) {
  141.       if (rpn) {
  142.     clrdisp++;
  143.       } else {
  144.         ringbell();
  145.         return(1);    /* the intent was probably not to do the operation */
  146.       }
  147.     }
  148.  
  149.     if (keynum != kCLR) CLR=0;
  150.     if (keynum != kOFF) OFF=0;
  151.     return(0);
  152. }
  153.  
  154. #ifndef IEEE
  155.  
  156. /* cannot assign result of setjmp under ANSI C, use global instead */
  157. static int SignalKind;
  158. static int SignalCode;
  159.  
  160. void fail_op()
  161. {
  162.     if (SignalKind == SIGFPE)
  163.     switch (SignalCode) {
  164. #ifdef SVR4
  165.       case FPE_INTDIV:        /* integer divide by zero */
  166.       case FPE_FLTDIV:        /* floating point divide by zero */
  167.     strcpy(dispstr, "divide by 0");
  168.     break;
  169.       case FPE_INTOVF:        /* integer overflow */
  170.       case FPE_FLTOVF:        /* floating point overflow */
  171.     strcpy(dispstr, "overflow");
  172.     break;
  173.       case FPE_FLTUND:        /* floating point underflow */
  174.     strcpy(dispstr, "underflow");
  175.     break;
  176.       case FPE_FLTRES:        /* floating point inexact result */
  177.     strcpy(dispstr, "inexact result");
  178.     break;
  179.       case FPE_FLTINV:        /* invalid floating point operation */
  180.     strcpy(dispstr, "invalid op");
  181.     break;
  182.       case FPE_FLTSUB:        /* subscript out of range */
  183.     strcpy(dispstr, "out of range");
  184.     break;
  185.  
  186. #endif /*SVR4*/
  187.  
  188. #ifdef FPE_FLTDIV_TRAP
  189.       case FPE_FLTDIV_TRAP:  strcpy(dispstr,"div by zero"); break;
  190. #endif
  191. #ifdef FPE_FLTDIV_FAULT
  192.            case FPE_FLTDIV_FAULT: strcpy(dispstr,"div by zero"); break;
  193. #endif
  194. #ifdef FPE_FLTOVF_TRAP
  195.            case FPE_FLTOVF_TRAP:  strcpy(dispstr,"overflow"); break;
  196. #endif
  197. #ifdef FPE_FLTOVF_FAULT
  198.            case FPE_FLTOVF_FAULT: strcpy(dispstr,"overflow"); break;
  199. #endif
  200. #ifdef FPE_FLTUND_TRAP
  201.            case FPE_FLTUND_TRAP:  strcpy(dispstr,"underflow"); break;
  202. #endif
  203. #ifdef FPE_FLTUND_FAULT
  204.            case FPE_FLTUND_FAULT: strcpy(dispstr,"underflow"); break;
  205. #endif
  206.            default:               strcpy(dispstr,"error");
  207.     }
  208.     else 
  209.     if (SignalKind == SIGILL)
  210.         strcpy(dispstr, "illegal operand");
  211.  
  212.     entered=3;
  213.     DrawDisplay();
  214.     return;
  215. }
  216.  
  217.  
  218. /* keep SVR4 compiler from complaining about scope of arg declaration below */
  219. typedef struct sigcontext * sigcontextstructp;
  220. /*ARGSUSED*/
  221. signal_t fperr(sig,code,scp)
  222.   int sig,code;
  223.   sigcontextstructp scp;
  224. {
  225. #ifdef SYSV
  226.     signal(SIGFPE,(signal_t (*)())fperr);
  227. #endif
  228.     SignalKind = sig;
  229.     SignalCode = code;
  230.     longjmp(env,1);
  231. }
  232.  
  233. /* for VAX BSD4.3 */
  234. /*ARGSUSED*/
  235. signal_t illerr(sig,code,scp)
  236.   int sig,code;
  237.   sigcontextstructp scp;
  238. {
  239.     /* not reset when caught? */
  240.     signal(SIGILL,(signal_t (*)())illerr);
  241.  
  242.     SignalKind = sig;
  243.     SignalCode = code;
  244.     longjmp(env,1);
  245. }
  246.  
  247. #endif    /* not IEEE */
  248.  
  249.  
  250. void post_op()
  251. {
  252. #ifdef DEBUG
  253.     showstack("\0");
  254. #endif
  255. #ifndef IEEE
  256.     if (errno) {
  257.         strcpy(dispstr,"error");
  258.         DrawDisplay();
  259.         entered=3;
  260.         errno=0;
  261.         }
  262. #endif
  263. }
  264. /*-------------------------------------------------------------------------*/
  265. DrawDisplay()
  266. {
  267.     if ((int) strlen(dispstr) > 12) {     /* strip out some decimal digits */
  268.         char tmp[32];
  269.         char *estr = index(dispstr,'e');  /* search for exponent part */
  270.         if (!estr) dispstr[12]='\0';      /* no exp, just trunc. */
  271.         else {
  272.             if ((int) strlen(estr) <= 4) 
  273.                 sprintf(tmp,"%.8s",dispstr); /* leftmost 8 chars */
  274.             else
  275.                 sprintf(tmp,"%.7s",dispstr); /* leftmost 7 chars */
  276.             strcat (tmp,estr);            /* plus exponent */
  277.             strcpy (dispstr,tmp);
  278.             }
  279.         }
  280.     draw(dispstr);
  281.     setflag(XCalc_MEMORY, (flagM));
  282.     setflag(XCalc_INVERSE, (flagINV));
  283.     setflag(XCalc_DEGREE, (drgmode==DEG));
  284.     setflag(XCalc_RADIAN, (drgmode==RAD));
  285.     setflag(XCalc_GRADAM, (drgmode==GRAD));
  286.     setflag(XCalc_PAREN, (flagPAREN));
  287. }
  288.  
  289. /*-------------------------------------------------------------------------*/
  290. numeric(keynum)
  291.      int keynum;
  292. {
  293.     char    st[2];
  294.     int        cell;
  295.  
  296.   flagINV=0;
  297.  
  298.   if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) {
  299.       switch (keynum) {
  300.     case kONE:    cell = 1; break;
  301.     case kTWO:    cell = 2; break;
  302.     case kTHREE:    cell = 3; break;
  303.     case kFOUR:    cell = 4; break;
  304.     case kFIVE:    cell = 5; break;
  305.     case kSIX:    cell = 6; break;
  306.     case kSEVEN:    cell = 7; break;
  307.     case kEIGHT:    cell = 8; break;
  308.     case kNINE:    cell = 9; break;
  309.     case kZERO:    cell = 0; break;
  310.       }
  311.       switch (memop) {
  312.       case kSTO:
  313.     mem[cell] = dnum;
  314.     lift_enabled = 1;
  315.       entered = 2;
  316.       clrdisp++;
  317.     break;
  318.       case kRCL:
  319.     PushNum(dnum);
  320.     dnum = mem[cell];
  321.     sprintf(dispstr, "%.8g", dnum);
  322.     lift_enabled = 1;
  323.         entered = 1;
  324.     clrdisp = 0;
  325.     break;
  326.       case kSUM:
  327.     mem[cell] += dnum;
  328.     lift_enabled = 1;
  329.       entered = 2;
  330.       clrdisp++;
  331.     break;
  332.       }
  333.       memop = kCLR;
  334.       DrawDisplay();
  335.       return;
  336.   }
  337.  
  338.   if (clrdisp) {
  339.     dispstr[0]='\0';
  340.     exponent=Dpoint=0;
  341. /*    if (rpn && entered==2)
  342.       PushNum(dnum);
  343.  */
  344.     if (rpn & lift_enabled)
  345.     PushNum(dnum);
  346.   }
  347.   if ((int) strlen(dispstr) >= MAXDISP)
  348.     return;
  349.     
  350.     switch (keynum){
  351.       case kONE:    st[0] = '1'; break;
  352.       case kTWO:    st[0] = '2'; break;
  353.       case kTHREE:    st[0] = '3'; break;
  354.       case kFOUR:    st[0] = '4'; break;
  355.       case kFIVE:    st[0] = '5'; break;
  356.       case kSIX:    st[0] = '6'; break;
  357.       case kSEVEN:    st[0] = '7'; break;
  358.       case kEIGHT:    st[0] = '8'; break;
  359.       case kNINE:    st[0] = '9'; break;
  360.       case kZERO:    st[0] = '0'; break;
  361.     }
  362.     st[1] = '\0';
  363.     strcat(dispstr,st);
  364.  
  365.   DrawDisplay();
  366.   if (clrdisp && keynum != kZERO)
  367.     clrdisp=0; /*no leading 0s*/
  368.   entered=1;
  369.   lift_enabled = 0;
  370. }
  371.  
  372. bkspf()
  373. {
  374.  
  375.   lift_enabled = 0;
  376.  
  377.   if (! flagINV)
  378.   {
  379.       if (entered!=1 || clrdisp)
  380.       return;
  381.       if ((int) strlen(dispstr) > 0)
  382.       dispstr[strlen(dispstr)-1] = 0;
  383.       if (strlen(dispstr) == 0) {
  384.       strcat(dispstr, "0");
  385.       clrdisp++;
  386.       }
  387.   }
  388.   else
  389.   {
  390.       strcpy(dispstr, "0");
  391.       dnum = 0.0;
  392.       clrdisp++;
  393.       flagINV = 0;
  394.   }
  395.   DrawDisplay();
  396. }
  397.  
  398. decf()
  399. {
  400.   flagINV=0;
  401.   if (clrdisp) {
  402.       if (rpn)
  403.     PushNum(dnum);
  404.       strcpy(dispstr,"0");
  405.   }
  406.   if (!Dpoint) {
  407.     strcat(dispstr,".");
  408.     DrawDisplay();
  409.     Dpoint++;
  410.   }
  411.   clrdisp=0;
  412.   entered=1;
  413. }
  414.  
  415. eef()
  416. {
  417.   flagINV=0;
  418.   if (clrdisp) {
  419.       if (rpn && lift_enabled)
  420.     PushNum(dnum);
  421.       strcpy(dispstr, rpn ? "1" : "0");
  422.   }
  423.   if (!exponent) {
  424.     strcat(dispstr,"E+");
  425.     DrawDisplay();
  426.     exponent=strlen(dispstr)-1;  /* where the '-' goes */
  427.   }
  428.   clrdisp=0;
  429.   entered=1;
  430. }
  431.  
  432. clearf()
  433. {
  434.   flagINV=0;
  435.   if (CLR && !rpn) { /* clear all */
  436.     ClearStacks();
  437.     flagPAREN=0;
  438.   }
  439.   CLR++;
  440.   exponent=Dpoint=0;
  441.   clrdisp=1;
  442.   entered=1;
  443.   strcpy(dispstr,"0");
  444.   DrawDisplay();
  445. }
  446.  
  447. negf()
  448. {
  449.   flagINV=0;
  450.   if (exponent) {       /* neg the exponent */
  451.     if (dispstr[exponent]=='-')
  452.       dispstr[exponent]='+';
  453.     else
  454.       dispstr[exponent]='-';
  455.     DrawDisplay();
  456.     return;
  457.   }
  458.  
  459.   if (strcmp("0",dispstr)==0)
  460.     return;            /* don't neg a zero */
  461.   if (dispstr[0]=='-')         /* already neg-ed */
  462.     strcpy(dispstr,dispstr+1);  /* move str left once */
  463.   else {            /* not neg-ed.  add a '-' */
  464.     char tmp[32];
  465.     sprintf(tmp,"-%s",dispstr);
  466.     strcpy(dispstr,tmp);
  467.   }
  468.   if (entered==2)
  469.     dnum = -1.0 * dnum;
  470.   DrawDisplay();
  471. }
  472.  
  473. /* Two operand functions for infix calc */
  474. twoop(keynum)
  475. {
  476.   double PopNum();
  477.  
  478.   if (flagINV) {
  479.     flagINV=0;
  480.     DrawDisplay();
  481.   }
  482.  
  483.   if (!entered) {        /* something like "5+*" */
  484.     if (!isopempty())
  485.       (void) PopOp();            /* replace the prev op */
  486.     PushOp(keynum);        /* with the new one */
  487.     return;
  488.   }
  489.   
  490.   if (entered==1)
  491.     parse_double(dispstr,"%lf",&dnum);
  492.  
  493.   clrdisp=CLR=1;
  494.   entered=Dpoint=exponent=0;
  495.  
  496.   if (!isopempty()) {  /* there was a previous op */
  497.     lastop=PopOp();   /* get it */
  498.  
  499.     if (lastop==kLPAR) {  /* put it back */
  500.       PushOp(kLPAR);
  501.       PushOp(keynum);
  502.       PushNum(dnum);
  503.       return;
  504.     }
  505.  
  506.     /* now, if the current op (keynum) is of
  507.        higher priority than the lastop, the current
  508.        op and number are just pushed on top 
  509.        Priorities:  (Y^X) > *,/ > +,- */
  510.     
  511.     if (priority(keynum) > priority(lastop)) {
  512.       PushNum(dnum);
  513.       PushOp(lastop);
  514.       PushOp(keynum);
  515.     } else {  /* execute lastop on lastnum and dnum, push
  516.            result and current op on stack */
  517.       acc=PopNum();
  518.       switch (lastop) { /* perform the operation */
  519.       case kADD: acc += dnum;  break;
  520.       case kSUB: acc -= dnum;  break;
  521.       case kMUL: acc *= dnum;  break;
  522.       case kDIV: acc /= dnum;  break;
  523.       case kPOW: acc =  pow(acc,dnum);  break;
  524.     }
  525.       PushNum(acc);
  526.       PushOp(keynum);
  527.       sprintf(dispstr,"%.8g",acc);
  528.       DrawDisplay();
  529.       dnum=acc;
  530.     }
  531.   }
  532.   else { /* op stack is empty, push op and num */
  533.     PushOp(keynum);
  534.     PushNum(dnum);
  535.   } 
  536. }                      
  537.  
  538. /* Two operand functions for rpn calc */
  539. twof(keynum)
  540. {
  541.   double PopNum();
  542.  
  543.   if (flagINV) {
  544.     flagINV=0;
  545.     DrawDisplay();
  546.   }
  547.   if (!entered)
  548.     return;
  549.   if (entered==1)
  550.     parse_double(dispstr, "%lf", &dnum);
  551.   acc = PopNum();
  552.   switch(keynum) {
  553.   case kADD: acc += dnum;  break;
  554.   case kSUB: acc -= dnum;  break;
  555.   case kMUL: acc *= dnum;  break;
  556.   case kDIV: acc /= dnum;  break;
  557.   case kPOW: acc =  pow(acc,dnum);  break;
  558.   case kXXY: PushNum(dnum);
  559.   }
  560.   sprintf(dispstr, "%.8g", acc);
  561.   DrawDisplay();
  562.   clrdisp++;
  563.   Dpoint = exponent = 0;
  564.   entered = 2;
  565.   lift_enabled = 1;
  566.   dnum = acc;
  567. }
  568.  
  569.  
  570. entrf()
  571. {
  572.   flagINV=0;
  573.   if (!entered)
  574.     return;
  575.  
  576.   clrdisp=CLR=1;
  577.   Dpoint=exponent=0;
  578.  
  579.   if (entered==1)
  580.     parse_double(dispstr,"%lf",&dnum);
  581.   entered=2;
  582.   memop = kENTR;
  583.   PushNum(dnum);
  584.   lift_enabled = 0;
  585. }
  586.  
  587. equf()
  588. {
  589.   double PopNum();
  590.  
  591.   flagINV=0;
  592.   if (!entered)
  593.     return;
  594.  
  595.   clrdisp=CLR=1;
  596.   Dpoint=exponent=0;
  597.  
  598.   if (entered==1)
  599.     parse_double(dispstr,"%lf",&dnum);
  600.   entered=2;
  601.  
  602.   PushNum(dnum);
  603.  
  604.   while (!isopempty()) {  /* do all pending ops */
  605.     dnum=PopNum();
  606.     acc=PopNum();
  607.     lastop=PopOp();
  608.     switch (lastop) {
  609.     case kADD:  acc += dnum;
  610.         break;
  611.     case kSUB:  acc -= dnum;
  612.         break;
  613.     case kMUL:  acc *= dnum;
  614.         break;
  615.     case kDIV:  acc /= dnum;
  616.         break;
  617.     case kPOW:  acc = pow(acc,dnum);
  618.         break;
  619.     case kLPAR:    flagPAREN--;
  620.         PushNum(acc);
  621.         break;
  622.     }
  623.     dnum=acc;
  624.     PushNum(dnum);
  625.   }
  626.  
  627.   sprintf(dispstr,"%.8g",dnum);
  628.   DrawDisplay();
  629. }
  630.         
  631. lparf()
  632. {
  633.   flagINV=0;
  634.   PushOp(kLPAR);
  635.   flagPAREN++;
  636.   DrawDisplay();
  637. }
  638.  
  639. rollf()
  640. {
  641.   double PopNum();
  642.  
  643.   if (!entered)
  644.     return;
  645.   if (entered==1)
  646.     parse_double(dispstr, "%lf", &dnum);
  647.   entered = 2;
  648.   lift_enabled = 1;
  649.   RollNum(flagINV);
  650.   flagINV=0;
  651.   clrdisp++;
  652.   sprintf(dispstr, "%.8g", dnum);
  653.   DrawDisplay();
  654. }
  655.  
  656. rparf()
  657. {
  658.   double PopNum();
  659.  
  660.   flagINV=0;
  661.   if (!entered)
  662.     return;
  663.  
  664.   if (!flagPAREN)
  665.     return;
  666.   
  667.   clrdisp++;
  668.   Dpoint=exponent=0;
  669.  
  670.   if (entered==1)
  671.     parse_double(dispstr,"%lf",&dnum);
  672.   entered=2;
  673.  
  674.   PushNum(dnum);
  675.   while (!isopempty() && (lastop=PopOp())!=kLPAR) {
  676.     /* do all pending ops, back to left paren */
  677.     dnum=PopNum();
  678.     acc=PopNum();
  679.     switch (lastop) {
  680.     case kADD:  acc += dnum;
  681.         break;
  682.     case kSUB:  acc -= dnum;
  683.         break;
  684.     case kMUL:  acc *= dnum;
  685.         break;
  686.     case kDIV:  acc /= dnum;
  687.         break;
  688.     case kPOW:  acc = pow(acc,dnum);
  689.         break;
  690.     }
  691.     dnum=acc;
  692.     PushNum(dnum);
  693.   }
  694.   (void) PopNum();
  695.   flagPAREN--;
  696.   entered=2;
  697.   sprintf(dispstr,"%.8g",dnum);
  698.   DrawDisplay();
  699. }
  700.  
  701. drgf()
  702. {
  703.   if (flagINV) {
  704.     if (entered==1)
  705.       parse_double(dispstr,"%lf",&dnum);
  706.     switch (drgmode) {
  707.     case DEG:  dnum=dnum*PI/180.0;    break;
  708.     case RAD:  dnum=dnum*200.0/PI;    break;
  709.     case GRAD: dnum=dnum*90.0/100.0;  break;
  710.     }
  711.     entered=2;
  712.     clrdisp=1;
  713.     flagINV=0;
  714.     sprintf(dispstr,"%.8g",dnum);
  715.   }
  716.                          
  717.   flagINV=0;
  718.   drgmode = (drgmode + 1) % 3;
  719.   switch (drgmode) {
  720.   case DEG:  drg2rad=PI / 180.0;
  721.          rad2drg=180.0 / PI;
  722.          break;
  723.   case RAD:  drg2rad=1.0;
  724.          rad2drg=1.0;
  725.          break;
  726.   case GRAD: drg2rad=PI / 200.0;
  727.          rad2drg=200.0 / PI;
  728.          break;
  729.   }
  730.   DrawDisplay();
  731. }
  732.  
  733. invf()
  734. {
  735.   flagINV = ~flagINV;
  736.   DrawDisplay();
  737. }
  738.  
  739. memf(keynum)
  740. {
  741.     memop = keynum;
  742.     if (entered==1)
  743.       parse_double(dispstr,"%lf",&dnum);
  744.     entered = 2;
  745.     clrdisp++;
  746.     lift_enabled = 0;
  747. }
  748.  
  749. oneop(keynum)
  750. {
  751.   int i,j;
  752.   double dtmp;
  753.  
  754.   if (entered==1)
  755.     parse_double(dispstr,"%lf",&dnum);
  756.   entered = 2;
  757.  
  758.   switch (keynum) {  /* do the actual math fn. */
  759.   case kE:     if (rpn && memop != kENTR) PushNum(dnum); dnum=E;  break;
  760.   case kPI:    if (rpn && memop != kENTR) PushNum(dnum); dnum=PI;  break;
  761.   case kRECIP: dnum=1.0/dnum;  break;
  762.   case kSQR:   flagINV = !flagINV; /* fall through to */
  763.   case kSQRT:  if (flagINV) dnum=dnum*dnum;
  764.            else dnum=sqrt(dnum);
  765.            break;
  766.   case k10X:   flagINV = !flagINV; /* fall through to */
  767.   case kLOG:   if (flagINV) dnum=pow(10.0,dnum);
  768.              else dnum=log10(dnum);
  769.            break;
  770.   case kEXP:   flagINV = !flagINV; /* fall through to */
  771.   case kLN:    if (flagINV) dnum=exp(dnum);
  772.            else dnum=log(dnum);
  773.            break;
  774.   case kSIN:   if (flagINV) dnum=asin(dnum)*rad2drg;
  775.            else dnum=sin(dnum*drg2rad);
  776.            break;
  777.   case kCOS:   if (flagINV) dnum=acos(dnum)*rad2drg;
  778.            else dnum=cos(dnum*drg2rad);
  779.            break;
  780.   case kTAN:   if (flagINV) dnum=atan(dnum)*rad2drg;
  781.            else dnum=tan(dnum*drg2rad);
  782.            break;
  783.   case kSTO:   mem[0]=dnum;  flagM=!(mem[0]==0.0);  break;
  784.   case kRCL:   if (rpn && lift_enabled) PushNum(dnum);
  785.                dnum=mem[0];  flagM=!(mem[0]==0.0);  break;
  786.   case kSUM:   mem[0]+=dnum; flagM=!(mem[0]==0.0);  break;
  787.   case kEXC:   dtmp=dnum; dnum=mem[0];  mem[0]=dtmp;
  788.            flagM=!(mem[0]==0.0);  break;
  789.   case kFACT:  if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) {
  790.          strcpy(dispstr,"error");
  791.          entered=3;
  792.          break;
  793.            }
  794.            i=(int) (floor(dnum));
  795.            for (j=1,dnum=1.0; j<=i; j++) 
  796.          dnum*=(float) j;
  797.            break;
  798.   }
  799.   
  800.   if (entered==3) {  /* error */
  801.     DrawDisplay();
  802.     return;
  803.   }
  804.  
  805.   entered=2;
  806.   clrdisp=1;
  807.   flagINV=0;
  808.   lift_enabled = 1;
  809.   sprintf(dispstr,"%.8g",dnum);
  810.   DrawDisplay();
  811. }
  812.  
  813. offf()
  814. {
  815.   /* full reset */
  816.   int i;
  817.   ResetCalc();
  818.   entered=clrdisp=1;
  819.   lift_enabled = 0;
  820.   dnum=mem[0]=0.0;
  821.   if (rpn)
  822.       for (i=1; i < XCALC_MEMORY; i++)
  823.       mem[i]=0.0;
  824.   accset=exponent=Dpoint=0;
  825.   DrawDisplay();
  826. }
  827.  
  828.  
  829. #define STACKMAX 32
  830. static int opstack[STACKMAX];
  831. static int opsp;
  832. static double numstack[STACKMAX];
  833. static int numsp;
  834.  
  835.  
  836. /*******/
  837. PushOp(op)
  838.    int op;
  839. /*******/
  840. {
  841.   if (opsp==STACKMAX) {strcpy(dispstr,"stack error");  entered=3;}
  842.   else opstack[opsp++]=op;
  843. }
  844.  
  845. /*******/
  846. int PopOp()
  847. /*******/
  848. {
  849.   if (opsp==0) {
  850.       strcpy(dispstr,"stack error");
  851.       entered=3;
  852.       return(kNOP);
  853.   } else
  854.     return(opstack[--opsp]);
  855. }
  856.  
  857. /*******/
  858. int isopempty()
  859. /*******/
  860. {
  861.   return( opsp ? 0 : 1 );
  862. }
  863.  
  864. #ifdef DEBUG
  865. showstack(string)
  866.     char    *string;
  867. {
  868.     fprintf(stderr, "%s: %lf %lf %lf\n", string, numstack[0], numstack[1],
  869.         numstack[2]);
  870. }
  871. #endif
  872.  
  873. /*******/
  874. PushNum(num)
  875.  double num;
  876. /*******/
  877. {
  878.   if (rpn) {
  879.       numstack[2] = numstack[1];
  880.       numstack[1] = numstack[0];
  881.       numstack[0] = num;
  882.       return;
  883.   }
  884.   if (numsp==STACKMAX) {
  885.       strcpy(dispstr,"stack error");
  886.       entered=3;
  887.   } else
  888.     numstack[numsp++]=num;
  889. }
  890.  
  891. /*******/
  892. double PopNum()
  893. /*******/
  894. {
  895.     if (rpn) {
  896.     double tmp = numstack[0];
  897.     numstack[0] = numstack[1];
  898.     numstack[1] = numstack[2];
  899.     return(tmp);
  900.     }
  901.     if (numsp==0) {
  902.     strcpy(dispstr,"stack error");
  903.     entered=3;
  904.     return 0.0;
  905.     } else
  906.       return(numstack[--numsp]);
  907. }
  908.  
  909. /*******/
  910. RollNum(dir)
  911. /*******/
  912. {
  913.     double tmp;
  914.  
  915.     if (dir) {                /* roll up */
  916.     tmp         = dnum;
  917.     dnum        = numstack[2];
  918.     numstack[2] = numstack[1];
  919.     numstack[1] = numstack[0];
  920.     numstack[0] = tmp;
  921.     } else {                /* roll down */
  922.     tmp         = dnum;
  923.     dnum        = numstack[0];
  924.     numstack[0] = numstack[1];
  925.     numstack[1] = numstack[2];
  926.     numstack[2] = tmp;
  927.     }
  928. }
  929.  
  930.  
  931. /*******/
  932. ClearStacks()
  933. /*******/
  934. {
  935.     if (rpn)
  936.       numstack[0] = numstack[1] = numstack[2] = 0.;
  937.     opsp=numsp=0;
  938. }
  939.  
  940.  
  941. /*******/
  942. int priority(op)
  943.          int op;
  944. /*******/
  945. {
  946.     switch (op) {
  947.         case kPOW: return(2);
  948.         case kMUL:
  949.         case kDIV: return(1);
  950.         case kADD:
  951.         case kSUB: return(0);
  952.         }
  953.     return 0;
  954. }
  955.  
  956.  
  957. /********/
  958. ResetCalc()
  959. /********/
  960. {
  961.     flagM=flagINV=flagPAREN=0;  drgmode=DEG;
  962.     setflag(XCalc_MEMORY, False);
  963.     setflag(XCalc_INVERSE, False);
  964.     setflag(XCalc_PAREN, False);
  965.     setflag(XCalc_RADIAN, False);
  966.     setflag(XCalc_GRADAM, False);
  967.     setflag(XCalc_DEGREE, True);
  968.     strcpy(dispstr,"0");
  969.     draw(dispstr);
  970.     ClearStacks();
  971.     drg2rad=PI/180.0;
  972.     rad2drg=180.0/PI;
  973. }
  974.